﻿#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
/***********12.深⼊理解指针(2)************/
/****1. const 修饰指针****/
//const修饰变量
//const是常属性-不能改变的属性

//int main()
//{
//	const int a = 10;//a变成了常变量，a的本质还是变量，但因为const修饰，不能改变
//
//	a = 1;
//	printf("%d\n",a);
//	return 0;
//}

//int main()
//{
//	const int n = 10;
//	int arr[n]; //err
//  return 0;
//}

//int main()
//{
//	const int a = 10;
//	int* p = &a;
//	*p = 1;
//	printf("%d\n",a);
//	return 0;
//}

//const 修饰指针变量
//可以放在*的左边，也可以放在*的右边，意义不一样
//const 放在*左边表示指针指向的内容，不能通过指针来改变了，但是指针变量本身是可以改变的
//const 放在*右边表示指针变量本身不能被修改，但指向的内容可以通过指针变量来改变

//int main()
//{
//	int a = 100;
//	int b = 1000;
//
//	//const int* p = &a;    //const在左
//	//*p = 0;//err
//	//p = &b;//ok
//
//	int* const p = &a;		//const在右
//	*p = 0;//ok
//	p = &b;//err
//
//	return 0;
//}

/*******2. 野指针******/
//野指针就是指针指向的位置是不可知的（随机的、不正确的、没有明确限制的）
//1. 指针未初始化
//int main()
//{
//	int* p;//局部变量不初始化，里面放的随机值
//
//	*p = 20;//非法访问，p就是野指针
//
//	return 0;
//}

//2. 指针越界访问
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* p = arr;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int i = 0;
//	for (i = 0;i <= sz;i++)//循环11次，p指向最后一个元素后面的空间，就越界了
//	{
//		*p = i;
//		printf("%d ",*p);
//		p++;
//	}
//	return 0;
//}

//3. 指针指向的空间释放
//int* test()
//{
//	int n = 100;//局部变量，出函数就释放了
//	return &n; 
//}
//int main()
//{
//	int* p = test();
//	printf("%d\n", *p);
//	return 0;
//}

/*如何规避野指针*/
//1.指针初始化
//int main()
//{
//	int a = 10; 
//	//如果明确知道指针指向哪⾥就直接赋值地址
//	int* p = &a;
//	
//	int* p2 = NULL;
//	//如果不知道指针应该指向哪⾥，可以给指针赋值NULL
//	if (p2 != NULL) 
//	{
//		*p = 200;
//	} 
//	return 0;
//}

//2.⼩⼼指针越界
//⼀个程序向内存申请了哪些空间，通过指针也就只能访问哪些空间，不能超出范围访问，超出了就是
//越界访问

//3.指针变量不再使⽤时，及时置NULL，指针使⽤之前检查有效性

//4.避免返回局部变量的地址上面的 3.指针指向的空间释放


/***************3. assert 断言****************/
//assert.h 头⽂件定义了宏assert()
//⽤于在运⾏时确保程序符合指定条件，如果不符合，就报
//错终⽌运⾏。这个宏常常被称为“断⾔”
//#define NDEBUG
//定义⼀个宏 NDEBUG,⽆需更改代码就能开启或关闭assert()的机制

#include <assert.h>

//int main()
//{
//	int arr[10] = { 1,2,3,4,5 };
//	int* p = arr;
//	assert(p != NULL);
//	int i = 0;
//	for (i = 0;i < 5;i++)
//	{
//		printf("%d ",*p);
//		p++;
//	}
//
//	return 0;
//}

/*int main()
{
	int arr[10] = { 1,2,3,4,5 };
	int* p = NULL;
	assert(p != NULL);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", *p);
		p++;
	} 
	return 0;
}  */               

//int main()
//{
//	int a = 5;
//	assert(a != 5);
//}

/*************4. 指针的使⽤和传址调⽤***************/

//strlen的模拟实现
//size_t my_strlen(const char* str)
//{
//	size_t count = 0;
//	assert(str != NULL);
//
//	//while (*str != '\0') //'\0'的ascll码值为零，0就为假，所以可以省略
//	while (*str)
//
//	{
//		count++;
//		str++;
//	}
//	return count;
//}
//
//int main()
//{
//	char arr[] = "abcdef";
//	size_t len = my_strlen(arr);
//	printf("%zd ", len);
//
//	return 0;
//}
 
/**传值调⽤和传址调⽤**/
//写⼀个函数，交换两个整型变量的值

//传值调用无法实现
//int Swap(int x, int y)//实参传递给形参的时候，形参是实参的一份临时拷贝，对形参的修改，不会影响实参
//{
//	int z = 0;
//	z = x;
//	x = y;
//	y = z;
//}
//
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//
//	Swap(a, b);
//	printf("%d %d",a, b);
//	return 0;
//}

//传址调用
//void Swap(int* px, int* py)
//{
//	int z = 0;
//	z = *px;
//	*px = *py;
//	*py = z;
//}
//
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//
//	Swap(&a, &b);
//	printf("%d %d",a, b);
//	return 0;
//}
